I never imagined I would focus on personal branding or creating a personal website. My primary goal was to enhance our software, RaaiVan —an enterprise KMS/DMS/CMS at InKnowTex— and support the company in navigating Iran's unstable economy.
I had never needed to seek a job or go through the interview process before. When I moved to Australia in 2022, I easily secured a position in Melbourne before even arriving.
It was only recently, in June 2024, after concluding my journey at IE, that I realised it’s not straightforward to prove my technical proficiency with just a CV and a few short interviews.
So, I decided to create a personal website to share my journey and experiences.
I faced a couple of challenges:
- I didn’t know what a personal website should look like.
- I didn’t want to spend a lot of time developing and maintaining a website.
For the first challenge, I looked at a few examples and gathered some ideas.
For the second challenge, I aimed for the simplest solution that met the following criteria:
- Easy development
- Free hosting
- Free content management and storage
My Solution
-
Developed the website using
Next.js 14
and itsapp router
. While I'm proficient inReact
, I didn't have much experience withNext.js
, especially with theapp router
introduced in the newer versions. -
Deployed the website to
Vercel
by integrating it with theGitHub
repository. Now, whenever I push to the main branch, it deploys automatically on Vercel. -
Used a free
Notion
account as a CMS, so I didn't need to worry about data and storage. -
Generated a dynamic sitemap and added it to
Google Search Console
. -
Bought a domain from
Namecheap
for13 AUD
. This was my only expense; everything else was free. This one is optional and you can use a sub-domain on Vercel.
Tech Stack
- Next.js 14
- React 18
- Typescript
- Tailwind CSS
- SASS Modules
- Styled Components
- Notion API
Technical Aspects
There were some technical decisions I needed to make and challenges to address. Let’s dive into them.
Why Next.js and not React?
When building a personal website for branding, good SEO
is essential. Therefore, it’s better to render pages server-side (SSR
) rather than client-side. In my case, the entire website is 100% server-side rendered. However, I might add features in the future that require client-side rendering, such as search or infinite scroll.
On the other hand, React
renders on the client side and isn’t ideal for websites that need strong search engine optimisation.
Another reason to choose Next.js over React is its simple routing mechanism. Next.js offers two major options: page router
and app router
. I used the app router, which is recommended in the newer versions of Next.js (version 14 in my case).
Routes
I defined three routes: one static route and two dynamic routes.
-
Home page:
/
-
Tag page:
/tag/[name]
-
Article page:
/article/[id]/[title]
When you deploy a Next.js app to Vercel, cache control headers are added automatically, so you don’t need to worry about them. However, there are cases where you might need to intervene.
By default, routes with a dynamic segment are not cached, meaning you get a fresh instance of the page each time you visit them. Static routes, like my home page (/
), are cached, which caused two problems for me:
-
The image URLs generated in
Notion
expire after a short time and if your static route displays images from notion, they won’t load after links expire. - When I publish, unpublish, or edit an article, the changes are not reflected on the home page.
To address these issues, I added the following line to the page.tsx
file that hosts the home page:
export const revalidate = 60;
This built-in functionality of the app router instructs Next.js to cache the page for a maximum of 60 seconds.
Integration with Notion
I used the npm package @notionhq/client
to interact with Notion APIs. It's user-friendly, and you can find more details on their GitHub page.
I created two databases
on Notion, one for the articles and one for my profile details. The articles have three main properties which are:
-
Title: of type
text
. -
Published: of type
checkbox
. Articles are displayed on the website only if theirPublished
flag is set totrue
. -
Tags: of type
multi_select
.
The Notion API returns page content as a JSON
object. To render this content as HTML, I used the npm package @notion-render/client
. However, it doesn't render all blocks properly, so I extended it and wrote custom CSS to ensure everything displayed correctly.